// use std::time;
use axum::{
    extract::{Path, State},
    http::header::HeaderMap,
    response::IntoResponse,
    Json,
};
use axum_macros::debug_handler;

use crate::app_state::state::SharedState;
use crate::types::{
    channel::{Request, Response},
    token,
    user::*,
};
use crate::utils::response::*;

use super::utils::{send_to_rauth_grpc_client_and_wait, send_to_redis_client_and_wait};

#[debug_handler]
// pub async fn register(Form(input): Form<RegisterRequest>) -> Result<Json<RegisterResult>, String> {
pub async fn register(
    State(state): State<SharedState>,
    Json(request): Json<RegisterRequest>,
) -> impl IntoResponse {
    dbg!(
        "Register user info: {}/{}",
        &request.email,
        &request.password
    );

    // In release version, should handle all errors and avoid panic
    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserRegister(request)).await {
        Ok(_) => ok(),
        Err(err) => error_with_message(&err),
    }
}

pub async fn login(
    State(state): State<SharedState>,
    Json(request): Json<LoginRequest>,
) -> impl IntoResponse {
    dbg!("Login user info: {}/{}", &request.email, &request.password);

    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserLogin(request)).await {
        Ok(rsp) => {
            if let Response::UserLogin(mut rsp) = rsp {
                match send_to_redis_client_and_wait(
                    state.clone(),
                    Request::TokenSet(token::TokenInfo {
                        token: rsp.new_token.clone(),
                        user_id: rsp.user_id.clone(),
                        expiration: rsp.token_expiration,
                    }),
                )
                .await
                {
                    Ok(_) => {
                        rsp.token_expiration = 0; // for safety, don't send expiration to client
                        ok_with_message_data("登录成功", rsp)
                    },
                    Err(err) => error_with_message(&err),
                }
            } else {
                panic!("Wrong login response type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn logout(
    State(state): State<SharedState>,
    Path(id): Path<String>,
    headers: HeaderMap,
) -> impl IntoResponse {
    dbg!("Logout user {}", &id);

    let token = headers.get("x-token");
    if token.is_none() {
        return error_with_message("Token 未提供");
    }

    match token.unwrap().to_str() {
        Ok(token) => {
            // delete token from redis
            match send_to_redis_client_and_wait(state.clone(), Request::TokenDelete(token.to_string()))
                .await
            {
                Ok(_) => ok_with_message("退出登录成功"),
                Err(err) => error_with_message(&err),
            }
        }
        Err(_) => return error_with_message("Token 未提供"),
    }
}

pub async fn update(
    State(state): State<SharedState>,
    Path(id): Path<String>,
    Json(request): Json<UserInfo>,
) -> impl IntoResponse {
    dbg!("Update user {}: {:#?}", &id, &request);

    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserUpdate(request)).await {
        Ok(_) => ok_with_message("用户更新成功"),
        Err(err) => error_with_message(&err),
    }
}

pub async fn change_password(
    State(state): State<SharedState>,
    Path(id): Path<String>,
    Json(request): Json<ChangePasswordRequest>,
) -> impl IntoResponse {
    dbg!("Change password {}: {:#?}", &id, &request);

    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserChangePassword(request)).await {
        Ok(_) => ok_with_message("密码更新成功"),
        Err(err) => error_with_message(&err),
    }
}

pub async fn get(State(state): State<SharedState>, Path(id): Path<String>) -> impl IntoResponse {
    dbg!("Get user {}", &id);

    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserGet(id)).await {
        Ok(rsp) => {
            if let Response::UserGet(rsp) = rsp {
                ok_with_message_data("用户信息获取成功", rsp)
            } else {
                panic!("Wrong login response type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn delete(State(state): State<SharedState>, Path(id): Path<String>) -> impl IntoResponse {
    dbg!("Delete user {}", &id);

    match send_to_rauth_grpc_client_and_wait(state.clone(), Request::UserDelete(id)).await {
        Ok(_) => ok_with_message("密码更新成功"),
        Err(err) => error_with_message(&err),
    }
}
